#define _GNU_SOURCE
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <dlfcn.h>
#include <string.h>
#include <stdbool.h> 
#include <pthread.h> 
#include <sys/time.h>
#include <sys/syscall.h>
#include <dlfcn.h>

typedef int MPI_Fint;

typedef int(*MPI_INIT)(int *argc, char ***argv);
typedef void(*MPI_INIT_FORTRAN)(MPI_Fint *ierr );

static void *handle = NULL;
static void *fortran_handle = NULL;

void check_addr(char* message, void* old_fn) {
    Dl_info dl_info;
    if (message == NULL) {
        message = "Default ";
    }
    if (old_fn && dladdr(old_fn, &dl_info)) {
        fprintf(stderr, "%s MPITRACER:  Loaded library: %s\n", message, dl_info.dli_fname);
        fprintf(stderr, "%s MPITRACER:  Base address: %p\n", message, dl_info.dli_fbase);
        fprintf(stderr, "%s MPITRACER:  Symbol name: %s\n", message, dl_info.dli_sname);
    }
}

void init_mpitracer(){
    fprintf(stderr, "MPITRACER: handle %p\n", handle);
    void* p3 = dlsym(fortran_handle, "MPI_Send");
        check_addr("p3", p3);
    // if (handle) {
        void* p1 = dlsym(handle, "MPI_Send");
        check_addr("p1", p1);
    // }
    // if (fortran_handle) {
        void* p2= dlsym(fortran_handle, "MPI_SEND");
        check_addr("p2", p2);
    // }

}

int MPI_Init(int *argc, char ***argv){
    static MPI_INIT old_fn= NULL;
    int ret=0;
    handle = dlopen("libmpi.so", RTLD_LAZY);
    old_fn= (MPI_INIT)dlsym(handle, "MPI_Init");
    check_addr("MPI_Init", old_fn);
    init_mpitracer();
    ret=old_fn(argc, argv);
    return ret;
}
typedef void *MPI_Comm;
typedef void *MPI_Datatype;
typedef int(*MPI_SEND)(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm);
int MPI_Send(const void *buf, int count, MPI_Datatype datatype, int dest,
    int tag, MPI_Comm comm){
    int ret = 0;
    return ret;
}

void mpi_init_(MPI_Fint *ierr){
    static MPI_INIT_FORTRAN old_fn= NULL;
    fortran_handle = dlopen("libmpi_mpifh.so", RTLD_LAZY);
    old_fn= (MPI_INIT_FORTRAN)dlsym(fortran_handle, "MPI_INIT");
    check_addr("mpi_init_", old_fn);
    init_mpitracer();
    old_fn(ierr);
}
